#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include<sqlite3.h>
#include<signal.h>
#include<unistd.h>
#include<time.h>



#define N 32
#define R 1//注册
#define L 2//登录
#define Q 3//查询
#define H 4//历史记录

#define DATABASE "my.db"


//定义通信双方的信息结构体
typedef struct{
    int type;
    char name[64];
    char data[128];
    }MSG;
    
int do_client(int acceptfd,sqlite3 *db);
int do_register(int acceptfd,MSG *msg,sqlite3 *db);
int do_login(int acceptfd,MSG *msg,sqlite3 *db);
int do_query(int acceptfd,MSG *msg,sqlite3 *db);
int do_history(int acceptfd,MSG *msg,sqlite3 *db);
int do_searchword(int acceptfd, MSG *msg, char word[]);
int get_date(char *date);
int history_callback(void* arg,int f_num,char** f_value,char** f_name);



// ./server 192.168.122.1 10000
int main(int argc,const char *argv[])
{
    struct sockaddr_in serveraddr;
    int n;
    sqlite3 *db;
    pid_t pid;
    int sockfd;
    int acceptfd;
    MSG msg;
    //如果传递参数不为3个，则提示用户输入正确的参数
    if(argc != 3)
    {
        printf("Usage:%s <serverIP> <PORT>\n",argv[0]);
        return -1;
    }
    //打开数据库
    if(sqlite3_open(DATABASE,&db)!=SQLITE_OK)
    {
        printf("%s\n",sqlite3_errmsg(db));
        return -1;
    }
    else{
        printf("open database success\n");
    }

    //创建套接字
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
    {
        perror("sockfd\n");
        return -1;
    }
    //初始化服务器的IP地址和端口号
    bzero(&serveraddr,sizeof(serveraddr));//清空结构体
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    serveraddr.sin_port=htons(atoi(argv[2])); 

    //绑定服务器的IP地址和端口号
    if(bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
    {
        perror("fail to bind\n");
        return -1;
    }
    //将套接字设置为监听状态
    if(listen(sockfd,5)<0)
    {
        perror("fail to listen\n");
        return -1;
    }
    
    signal(SIGCHLD,SIG_IGN);//忽略子进程退出时的信号，处理僵尸进程

    while(1)
    {
        //接收客户端的连接请求
        if(acceptfd=accept(sockfd,NULL,NULL)<0)
        {
            perror("fail to accept\n");
            return -1;
        }
        else{
            printf("accept success\n");
        }
        //创建子进程
        if((pid=fork())<0)
        {
            perror("fail to fork\n");
            return -1;
        }
        else if(pid==0) //儿子进程
        {
            //处理客户端的请求
            close(acceptfd);
            do_client(acceptfd,db);
            break;
        }
        else{
            close(acceptfd);
        }  
    }
    return 0;
}
int do_client(int acceptfd,sqlite3 *db)
{
    MSG msg;
    while (recv(acceptfd,&msg,sizeof(msg),0)>0)
    {
        printf("type=%d\n",msg.type);
        switch(msg.type)
        {
            case R:
                do_register(acceptfd,&msg,db);
                break;
            case L:
                do_login(acceptfd,&msg,db);
                break;
            case Q:
                do_query(acceptfd,&msg, db);
                break;
            case H:
                do_history(acceptfd,&msg,db);
                break;
            default:
                printf("Input error!\n");
                break;
        }
    }
    {
        printf("client quit!\n");
        close(acceptfd);
        exit(0);
    }
    
}

int do_register(int acceptfd,MSG *msg,sqlite3 *db)
{
    char sql[128];
    char *errmsg;//用于存放错误信息
    sprintf(sql,"insert into usr values('%s','%s')",msg->name,msg->data);//将注册信息插入数据库
    printf("%s\n",sql);
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
    {
        printf("%s\n",errmsg);
        strcpy(msg->data,"Register failed!");
    }
    else{
        printf("Register success!\n");
        strcpy(msg->data,"Register success!");
    }
    if(send(acceptfd,msg,sizeof(MSG),0)<0)
    {
        perror("send\n");
        return -1;
    }
    return 0;
}

int do_login(int acceptfd,MSG *msg,sqlite3 *db)
{
    char sql[128];
    char *errmsg,**result;
    int nrow,ncolumn;//nrow为查询结果的行数，ncolumn为查询结果的列数
    sprintf(sql,"select * from usr where name='%s' and passwd='%s'",msg->name,msg->data);//查询数据库中是否有该用户
    printf("%s\n",sql);
    if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg)!=SQLITE_OK)//查询成功返回SQLITE_OK
    {
        printf("%s\n",errmsg);
        return -1;
    
    }
    else{
        printf("Query success!\n");
        if(nrow==1)//查询结果只有一行，说明有该用户
        {
            strcpy(msg->data,"OK");//将查询结果返回给客户端
            send(acceptfd,msg,sizeof(MSG),0);
            return 1;
        }
        else{
            strcpy(msg->data,"User or passwd is wrong!");
            send(acceptfd,msg,sizeof(MSG),0);//将查询结果返回给客户端
            return 0;
        }
    }
    return 0;

}
int do_searchword(int acceptfd, MSG *msg, char word[])
{
	FILE * fp;
	int len = 0;
	char temp[512] = {};
	int result;
	char *p;


	//打开文件，读取文件，进行比对
	
	if((fp = fopen("dict.txt", "r")) == NULL)
	{
		perror("fail to fopen.\n");
		strcpy(msg->data, "Failed to open dict.txt");
		send(acceptfd, msg, sizeof(MSG), 0);
		return -1;
	}

	//打印出，客户端要查询的单词
	len = strlen(word);
	printf("%s , len = %d\n", word, len);

	//读文件，来查询单词
	while(fgets(temp, 512, fp) != NULL)
	{

	//	printf("temp:%s\n", temp);

		// abandon  ab
		result = strncmp(temp,word,len);

		if(result < 0)
		{
			continue;
		}
		if(result > 0 || ((result == 0) && (temp[len]!=' ')))
		{
			break;
		}

		// 表示找到了，查询的单词
		p = temp + len; //  abandon   v.akdsf dafsjkj 
	//	printf("found word:%s\n", p);
		while(*p == ' ')
		{
			p++;
		}

		// 找到了注释，跳跃过所有的空格
		strcpy(msg->data, p);
		printf("found word:%s\n", msg->data);

		// 注释拷贝完毕之后，应该关闭文件
		fclose(fp);
		return 1;
	}

	fclose(fp);

	return 0;
}

int get_date(char *data)
{
    time_t t;
    struct tm *tp;
    //获取当前系统时间
    time(&t);
    //将当前系统时间转换为本地时间
    tp=localtime(&t);
    //将当前系统时间转换为字符串格式
    sprintf(data,"%d-%d-%d %d:%d:%d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
    return 0;
}

int do_query(int acceptfd,MSG *msg,sqlite3 *db)
{ 
    char word[64];
    int found=0;
    char data[128];
    char sql[128];
    char *errmsg;
    //拿出msg结构体中要查询的单词
    strcpy(word,msg->data);
    found=do_serchword(acceptfd,msg,word);//在字典文件中查询该单词
    if(found==0)
    {
        strcpy(msg->data,"Not found!");
    }
    else{
        //获取系统时间
        get_date(data);
        //将查询结果插入数据库
        sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,data,word);
        printf("%s\n",sql);
        if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
        {
            printf("%s\n",errmsg);
        }
        else{
            printf("Insert success!\n");
        }
    }
    
}
int do_serchword(int acceptfd,MSG *msg,char *word)
{
    FILE *fp;
    char line[256];
    char tmp[256];
    int found=0;
    int len;
    int result;
    char *p;
    


    fp=fopen("dict.txt","r");//打开字典文件
    if(fp==NULL)
    {
        perror("fopen\n");
        strcpy(msg->data,"Not found!");
        send(acceptfd,msg,sizeof(MSG),0);
        return -1;
    }
    // 打印出客户端要查询的单词
    len=strlen(word);
    printf("%s,len=%d\n",word,len);
    //读文件查询单词
    while(fgets(line,256,fp)!=NULL)
    {
        result=strncmp(line,word,len);
        if(result<0)
        {
            continue;
        }
        if(result>0||line[len]!=' ')
        {
            break;
        }
        //找到了
        p=line+len;//指向单词解释的首地址
        while(*p==' ')
        {
            p++;
        }
        //找到了单词解释的首地址，拷贝单词解释
        strcpy(msg->data,p);
        //拷贝成功之后，关闭文件，返回
        fclose(fp);
        return 1;
    }
    fclose(fp);
    return 0;
    
}

int history_callback(void* arg,int f_num,char** f_value,char** f_name)
{
	// record  , name  , date  , word 
	int acceptfd;
	MSG msg;

	acceptfd = *((int *)arg);

	sprintf(msg.data, "%s , %s", f_value[1], f_value[2]);

	send(acceptfd, &msg, sizeof(MSG), 0);

	return 0;
}

int do_history(int acceptfd,MSG *msg,sqlite3 *db)
{
    char sql[128];
    char *errmsg,**result;//errmsg用于存放错误信息，result用于存放查询结果
    int nrow,ncolumn;
    sprintf(sql,"select * from usr where name='%s'",msg->name);//查询数据库中是否有该用户
    printf("%s\n",sql);
    if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg)!=SQLITE_OK)
    {
        printf("%s\n",errmsg);
    }
    else{
        printf("Query success!\n");
        strcpy(msg->data,"OK");
    }
    if(send(acceptfd,msg,sizeof(MSG),0)<0)
    {
        perror("send\n");
        return -1;
    }
    return 0;
}
